/**
 * 
 */
package iqq.app.ui.bean;

import iqq.app.util.Benchmark;
import iqq.im.bean.QQUser;

import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;

import javax.swing.AbstractListModel;

/**
 * Copy from DefaultListModel
 * 
 * @author ZhiHui_Chen<6208317@qq.com>
 * @create date 2013-4-11
 */
public class GroupMemberListModel extends AbstractListModel {
    private static final long serialVersionUID = 6729206849900604988L;

    private Vector delegate = new Vector();
    private Comparator<UserListElement> comparator;

    public GroupMemberListModel() {

    }

    public GroupMemberListModel(Comparator<UserListElement> comparator) {
        this.comparator = comparator;
    }

    public void sort() {
        if (comparator != null && delegate != null) {
            Benchmark.start("GroupMemberListModelSort");
            Collections.sort(delegate, comparator);
            Benchmark.end("GroupMemberListModelSort");
        }
    }

    public void update(QQUser user) {
        for (int i = 0; i < delegate.size(); i++) {
            UserListElement elt = (UserListElement) delegate.get(i);
            if (elt.hashCode() == user.hashCode()) {
                this.fireContentsChanged(this, i, i);
                break;
            }
        }
    }

    public void update(Object obj) {
        int index = delegate.indexOf(obj);
        this.fireContentsChanged(this, index, index);
    }

    public void update(int index) {
        this.fireContentsChanged(this, index, index);
    }

    public void updateAll() {
        Benchmark.start("GroupMemberListModelUpdateAll");
        this.fireContentsChanged(this, 0, delegate.size() - 1);
        Benchmark.end("GroupMemberListModelUpdateAll");
    }

    /**
     * Returns the number of components in this list.
     * <p/>
     * This method is identical to <code>size</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. This method exists in conjunction with <code>setSize</code> so that <code>size</code> is identifiable as a JavaBean property.
     * 
     * @return the number of components in this list
     * @see #size()
     */
    public int getSize() {
        return delegate.size();
    }

    /**
     * Returns the component at the specified index. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>get(int)</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @param index an index into this list
     * @return the component at the specified index
     * @throws ArrayIndexOutOfBoundsException if the <code>index</code> is negative or greater than the current size of this list
     * @see #get(int)
     */
    public Object getElementAt(int index) {
        return delegate.elementAt(index);
    }

    /**
     * Copies the components of this list into the specified array. The array must be big enough to hold all the objects in this list, else an <code>IndexOutOfBoundsException</code> is thrown.
     * 
     * @param anArray the array into which the components get copied
     * @see Vector#copyInto(Object[])
     */
    public void copyInto(Object anArray[]) {
        delegate.copyInto(anArray);
    }

    /**
     * Trims the capacity of this list to be the list's current size.
     * 
     * @see Vector#trimToSize()
     */
    public void trimToSize() {
        delegate.trimToSize();
    }

    /**
     * Increases the capacity of this list, if necessary, to ensure that it can hold at least the number of components specified by the minimum capacity argument.
     * 
     * @param minCapacity the desired minimum capacity
     * @see Vector#ensureCapacity(int)
     */
    public void ensureCapacity(int minCapacity) {
        delegate.ensureCapacity(minCapacity);
    }

    /**
     * Sets the size of this list.
     * 
     * @param newSize the new size of this list
     * @see Vector#setSize(int)
     */
    public void setSize(int newSize) {
        int oldSize = delegate.size();
        delegate.setSize(newSize);
        if (oldSize > newSize) {
            fireIntervalRemoved(this, newSize, oldSize - 1);
        } else if (oldSize < newSize) {
            fireIntervalAdded(this, oldSize, newSize - 1);
        }
    }

    /**
     * Returns the current capacity of this list.
     * 
     * @return the current capacity
     * @see Vector#capacity()
     */
    public int capacity() {
        return delegate.capacity();
    }

    /**
     * Returns the number of components in this list.
     * 
     * @return the number of components in this list
     * @see Vector#size()
     */
    public int size() {
        return delegate.size();
    }

    /**
     * Tests whether this list has any components.
     * 
     * @return <code>true</code> if and only if this list has no components, that is, its size is zero; <code>false</code> otherwise
     * @see Vector#isEmpty()
     */
    public boolean isEmpty() {
        return delegate.isEmpty();
    }

    /**
     * Returns an enumeration of the components of this list.
     * 
     * @return an enumeration of the components of this list
     * @see Vector#elements()
     */
    public Enumeration<?> elements() {
        return delegate.elements();
    }

    /**
     * Tests whether the specified object is a component in this list.
     * 
     * @param elem an object
     * @return <code>true</code> if the specified object is the same as a component in this list
     * @see Vector#contains(Object)
     */
    public boolean contains(Object elem) {
        return delegate.contains(elem);
    }

    /**
     * Searches for the first occurrence of <code>elem</code>.
     * 
     * @param elem an object
     * @return the index of the first occurrence of the argument in this list; returns <code>-1</code> if the object is not found
     * @see Vector#indexOf(Object)
     */
    public int indexOf(Object elem) {
        return delegate.indexOf(elem);
    }

    /**
     * Searches for the first occurrence of <code>elem</code>, beginning the search at <code>index</code>.
     * 
     * @param elem an desired component
     * @param index the index from which to begin searching
     * @return the index where the first occurrence of <code>elem</code> is found after <code>index</code>; returns <code>-1</code> if the <code>elem</code> is not found in the list
     * @see Vector#indexOf(Object, int)
     */
    public int indexOf(Object elem, int index) {
        return delegate.indexOf(elem, index);
    }

    /**
     * Returns the index of the last occurrence of <code>elem</code>.
     * 
     * @param elem the desired component
     * @return the index of the last occurrence of <code>elem</code> in the list; returns <code>-1</code> if the object is not found
     * @see Vector#lastIndexOf(Object)
     */
    public int lastIndexOf(Object elem) {
        return delegate.lastIndexOf(elem);
    }

    /**
     * Searches backwards for <code>elem</code>, starting from the specified index, and returns an index to it.
     * 
     * @param elem the desired component
     * @param index the index to start searching from
     * @return the index of the last occurrence of the <code>elem</code> in this list at position less than <code>index</code>; returns <code>-1</code> if the object is not found
     * @see Vector#lastIndexOf(Object, int)
     */
    public int lastIndexOf(Object elem, int index) {
        return delegate.lastIndexOf(elem, index);
    }

    /**
     * Returns the component at the specified index. Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is negative or not less than the size of the list. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>get(int)</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @param index an index into this list
     * @return the component at the specified index
     * @see #get(int)
     * @see Vector#elementAt(int)
     */
    public Object elementAt(int index) {
        return delegate.elementAt(index);
    }

    /**
     * Returns the first component of this list. Throws a <code>NoSuchElementException</code> if this vector has no components.
     * 
     * @return the first component of this list
     * @see Vector#firstElement()
     */
    public Object firstElement() {
        return delegate.firstElement();
    }

    /**
     * Returns the last component of the list. Throws a <code>NoSuchElementException</code> if this vector has no components.
     * 
     * @return the last component of the list
     * @see Vector#lastElement()
     */
    public Object lastElement() {
        return delegate.lastElement();
    }

    /**
     * Sets the component at the specified <code>index</code> of this list to be the specified object. The previous component at that position is discarded.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is invalid. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>set(int,Object)</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @param obj what the component is to be set to
     * @param index the specified index
     * @see #set(int, Object)
     * @see Vector#setElementAt(Object, int)
     */
    public void setElementAt(Object obj, int index) {
        delegate.setElementAt(obj, index);
        fireContentsChanged(this, index, index);
    }

    /**
     * Deletes the component at the specified index.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is invalid. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>remove(int)</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @param index the index of the object to remove
     * @see #remove(int)
     * @see Vector#removeElementAt(int)
     */
    public void removeElementAt(int index) {
        delegate.removeElementAt(index);
        fireIntervalRemoved(this, index, index);
    }

    /**
     * Inserts the specified object as a component in this list at the specified <code>index</code>.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is invalid. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>add(int,Object)</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @param obj the component to insert
     * @param index where to insert the new component
     * @throws ArrayIndexOutOfBoundsException if the index was invalid
     * @see #add(int, Object)
     * @see Vector#insertElementAt(Object, int)
     */
    public void insertElementAt(Object obj, int index) {
        delegate.insertElementAt(obj, index);
        fireIntervalAdded(this, index, index);
    }

    /**
     * Adds the specified component to the end of this list.
     * 
     * @param obj the component to be added
     * @see Vector#addElement(Object)
     */
    public void addElement(Object obj) {
        int index = delegate.size();
        delegate.addElement(obj);
        fireIntervalAdded(this, index, index);
    }

    /**
     * Adds the specified components to the end of this list.
     * 
     * @param objects the components to be added
     */
    public void addElements(List objects) {
        int index = delegate.size();
        delegate.addAll(objects);
        fireIntervalAdded(this, index, delegate.size());
    }

    /**
     * Removes the first (lowest-indexed) occurrence of the argument from this list.
     * 
     * @param obj the component to be removed
     * @return <code>true</code> if the argument was a component of this list; <code>false</code> otherwise
     * @see Vector#removeElement(Object)
     */
    public boolean removeElement(Object obj) {
        int index = indexOf(obj);
        boolean rv = delegate.removeElement(obj);
        if (index >= 0) {
            fireIntervalRemoved(this, index, index);
        }
        return rv;
    }

    /**
     * Removes all components from this list and sets its size to zero. <blockquote> <b>Note:</b> Although this method is not deprecated, the preferred method to use is <code>clear</code>, which implements the <code>List</code> interface defined in the 1.2 Collections framework. </blockquote>
     * 
     * @see #clear()
     * @see Vector#removeAllElements()
     */
    public void removeAllElements() {
        int index1 = delegate.size() - 1;
        delegate.removeAllElements();
        if (index1 >= 0) {
            fireIntervalRemoved(this, 0, index1);
        }
    }

    /**
     * Returns a string that displays and identifies this object's properties.
     * 
     * @return a String representation of this object
     */
    public String toString() {
        return delegate.toString();
    }

    /*
     * The remaining methods are included for compatibility with the Java 2 platform Vector class.
     */

    /**
     * Returns an array containing all of the elements in this list in the correct order.
     * 
     * @return an array containing the elements of the list
     * @see Vector#toArray()
     */
    public Object[] toArray() {
        Object[] rv = new Object[delegate.size()];
        delegate.copyInto(rv);
        return rv;
    }

    /**
     * Returns the element at the specified position in this list.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out of range (<code>index &lt; 0 || index &gt;=
     * size()</code>).
     * 
     * @param index index of element to return
     */
    public Object get(int index) {
        return delegate.elementAt(index);
    }

    /**
     * Replaces the element at the specified position in this list with the specified element.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out of range (<code>index &lt; 0 || index &gt;=
     * size()</code>).
     * 
     * @param index index of element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     */
    public Object set(int index, Object element) {
        Object rv = delegate.elementAt(index);
        delegate.setElementAt(element, index);
        fireContentsChanged(this, index, index);
        return rv;
    }

    /**
     * Inserts the specified element at the specified position in this list.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out of range (<code>index &lt; 0 || index &gt; size()</code>).
     * 
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     */
    public void add(int index, Object element) {
        delegate.insertElementAt(element, index);
        fireIntervalAdded(this, index, index);
    }

    /**
     * Removes the element at the specified position in this list. Returns the element that was removed from the list.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index is out of range (<code>index &lt; 0 || index &gt;=
     * size()</code>).
     * 
     * @param index the index of the element to removed
     */
    public Object remove(int index) {
        Object rv = delegate.elementAt(index);
        delegate.removeElementAt(index);
        fireIntervalRemoved(this, index, index);
        return rv;
    }

    /**
     * Removes all of the elements from this list. The list will be empty after this call returns (unless it throws an exception).
     */
    public void clear() {
        int index1 = delegate.size() - 1;
        delegate.removeAllElements();
        if (index1 >= 0) {
            fireIntervalRemoved(this, 0, index1);
        }
    }

    /**
     * Deletes the components at the specified range of indexes. The removal is inclusive, so specifying a range of (1,5) removes the component at index 1 and the component at index 5, as well as all components in between.
     * <p/>
     * Throws an <code>ArrayIndexOutOfBoundsException</code> if the index was invalid. Throws an <code>IllegalArgumentException</code> if <code>fromIndex &gt; toIndex</code>.
     * 
     * @param fromIndex the index of the lower end of the range
     * @param toIndex the index of the upper end of the range
     * @see #remove(int)
     */
    public void removeRange(int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IllegalArgumentException("fromIndex must be <= toIndex");
        }
        for (int i = toIndex; i >= fromIndex; i--) {
            delegate.removeElementAt(i);
        }
        fireIntervalRemoved(this, fromIndex, toIndex);
    }
}
